package task02;

import java.util.*;

public class CustomMap<T extends Object, A extends Object> implements Map {

    private CustomEntry<T, A>[] enteties;
    private CustomEntry<T, A>[] template;

    public CustomMap() {
        enteties = new CustomEntry[0];
        template = new CustomEntry[0];
    }

    @Override
    public int size() {
        return enteties.length;
    }

    @Override
    public boolean isEmpty() {
        if (enteties.length > 0) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public boolean containsKey(Object key) {
        for (int i = 0; i < enteties.length; i++) {
            if (enteties[i].getKey().equals(key)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean containsValue(Object value) {
        for (int i = 0; i < enteties.length; i++) {
            if (enteties[i].getValue().equals(value)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Object get(Object key) {
        for (int i = 0; i < enteties.length; i++) {
            Entry<T, A> entetie = enteties[i];
            if (entetie.getKey().equals(key)) {
                return entetie.getValue();
            }
        }
        return null;
    }

    @Override
    public Object put(Object key, Object value) {
        CustomEntry<T, A> entetie = new CustomEntry<T, A>(key, value);
        enteties = Arrays.copyOf(enteties, enteties.length + 1);
        enteties[enteties.length - 1] = entetie;
        return null;
    }

    @Override
    public Object remove(Object key) {
        int itterator = 0;
        template = Arrays.copyOf(enteties, enteties.length);
        enteties = new CustomEntry[enteties.length - 1];
        for (int i = 0; i < template.length; i++) {
            CustomEntry<T, A> entetie = template[i];
            if (!(entetie.key.equals(key))) {
                enteties[itterator] = entetie;
                itterator++;
            }
        }
        return enteties;
    }

    @Override
    public void putAll(Map m) {
        int oldSize = enteties.length;
        int newSize = enteties.length + m.size();
        Set<Entry<T, A>> entry = m.entrySet();
        Iterator iterator = entry.iterator();

        enteties = Arrays.copyOf(enteties, newSize);

        int itterator = oldSize;
        while (iterator.hasNext()) {
            Entry<T, A> templateEntry = (Entry<T, A>) iterator.next();
            CustomEntry<T, A> arrayEntry = new CustomEntry<T, A>(templateEntry.getKey(), templateEntry.getValue());
            enteties[itterator] = arrayEntry;
            itterator++;
        }
    }

    @Override
    public void clear() {
        enteties = new CustomEntry[0];
    }

    @Override
    public Set keySet() {
        return new HashSet(Arrays.asList(getKeysArray()));
    }

    @Override
    public Collection values() {
        return Arrays.asList(getValuesArray());
    }

    @Override
    public Set<Entry> entrySet() {
        return new HashSet<Entry>(Arrays.asList(enteties));
    }

    private A[] getValuesArray() {
        Object[] valuesArray = new Object[enteties.length];

        for (int i = 0; i < enteties.length; i++) {
            CustomEntry<T, A> entry = enteties[i];
            valuesArray[i] = entry.value;
        }

        return (A[]) valuesArray;
    }

    private T[] getKeysArray() {
        Object[] keysArray = new Object[enteties.length];

        for (int i = 0; i < enteties.length; i++) {
            CustomEntry<T, A> entry = enteties[i];
            keysArray[i] = entry.key;
        }

        return (T[]) keysArray;
    }

    private class CustomEntry<T, A> implements Entry<T, A> {
        T key;
        A value;

        private CustomEntry(Object key, Object value) {
            this.key = (T) key;
            this.value = (A) value;
        }

        @Override
        public T getKey() {
            return key;
        }

        @Override
        public A getValue() {
            return value;
        }

        @Override
        public A setValue(A value) {
            return this.value = value;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            CustomEntry that = (CustomEntry) o;

            if (key != null ? !key.equals(that.key) : that.key != null) return false;
            if (value != null ? !value.equals(that.value) : that.value != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = key != null ? key.hashCode() : 0;
            result = 31 * result + (value != null ? value.hashCode() : 0);
            return result;
        }
    }

}
